package mspbots.data.tl.prod.quickbooks.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.Lists;
import lombok.extern.log4j.Log4j2;
import mspbots.data.tl.base.AbstractBaseServiceImpl;
import mspbots.data.tl.entity.ResultEntity;
import mspbots.data.tl.prod.quickbooks.mapper.OnlineGeneralLedgerMapper;
import mspbots.data.tl.prod.quickbooks.model.OnlineGeneralLedger;
import mspbots.data.tl.prod.quickbooks.service.OnlineGeneralLedgerService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Jay.Yang
 */

@Service
@Log4j2
@DS("master")
public class OnlineGeneralLedgerServiceImpl extends AbstractBaseServiceImpl<OnlineGeneralLedgerMapper,
        OnlineGeneralLedger> implements OnlineGeneralLedgerService {

    @Override
    public void sync(ResultEntity resultEntity) {
        JsonNode entity = resultEntity.getEntity();
        JsonNode header = entity.get("Header");
        if (ObjectUtils.isEmpty(header)){
            return;
        }
        OnlineGeneralLedger data = OnlineGeneralLedger.builder()
                .timePeriod(super.getStringValue(entity.get("timePeriod")))
                .time(super.getDateTimeValue(header.get("Time")))
                .currency(super.getStringValue(header.get("Currency")))
                .startPeriod(super.getDateValue(header.get("StartPeriod")))
                .endPeriod(super.getDateValue(header.get("EndPeriod")))
                .reportName(super.getStringValue(header.get("ReportName")))
                .reportBasis(super.getStringValue(header.get("ReportBasis")))
                .syncTime(resultEntity.getSyncDate())
                .build();
        data.setTenantCode(resultEntity.getTenantId());
        setHeaderOption(data, header.get("Option"));

        List<OnlineGeneralLedger> dataList = new ArrayList<>();
        setRows(dataList, data, entity.get("Rows"),true);
        dataList.forEach(data1 -> {
            data1.setKey(data1.getTenantCode() + data1.getTimePeriod() + data1.getName() +
                    (ObjectUtils.isEmpty(data1.getAccountName()) ? "" : data1.getAccountName()));
            OnlineGeneralLedger dbData = super.baseMapper.selectOne(Wrappers.<OnlineGeneralLedger>lambdaQuery()
                    .eq(OnlineGeneralLedger::getKey, data1.getKey())
                    .last("limit 1"));

            if (ObjectUtils.isEmpty(dbData)) {
                super.baseMapper.insert(data1);
            } else {
                data1.setId(dbData.getId());
                super.baseMapper.updateById(data1);
            }
        });
    }

    private void setHeaderOption(OnlineGeneralLedger data, JsonNode option) {
        if (ObjectUtils.isEmpty(option)) {
            return;
        }
        Iterator<JsonNode> optionIterator = option.elements();
        while (optionIterator.hasNext()) {
            JsonNode next = optionIterator.next();
            String name = super.getStringValue(next.get("Name"));
            if ("NoReportData".equalsIgnoreCase(name)) {
                data.setNoReportData(super.getBooleanValue(next.get("Value")));
            }
        }
    }

    private void setRows(List<OnlineGeneralLedger> dataList, OnlineGeneralLedger data, JsonNode rows, Boolean isRoot) {
        if (ObjectUtils.isEmpty(rows) || ObjectUtils.isEmpty(rows.get("Row"))) {
            return;
        }
        List<JsonNode> list = Lists.newArrayList(rows.get("Row").elements());
        String type = super.getStringValue(list.get(0).get("type"));
        data.setType(type);
        if ("Data".equalsIgnoreCase(type)){
            this.setColData(data, list);
        }else if("Section".equalsIgnoreCase(type)) {
            for (JsonNode row : list){
                this.rowSection(dataList, data, row,isRoot);
            }
        }
    }

    private void rowSection(List<OnlineGeneralLedger> dataList, OnlineGeneralLedger data, JsonNode row, Boolean isRoot) {
        OnlineGeneralLedger baseData = OnlineGeneralLedger.builder().build();
        BeanUtils.copyProperties(data, baseData);
        if (ObjectUtils.isEmpty(row.get("Header"))) {
            return;
        }
        this.setHeaderColData(baseData, row.get("Header").get("ColData"), isRoot);
        OnlineGeneralLedger rowData = OnlineGeneralLedger.builder().build();
        if (!ObjectUtils.isEmpty(row.get("Rows"))) {
            BeanUtils.copyProperties(baseData, rowData);
            this.setRows(dataList, rowData, row.get("Rows"), false);
        }
        if (isRoot){
            long count = dataList.stream()
                    .filter(d -> d.getAccountName().equals(baseData.getAccountName()) && d.getSubAccountName() != null)
                    .count();
            if (count > 0){
                return;
            }
        }
        baseData.setBalance(rowData.getBalance());
        baseData.setBeginningBalance(rowData.getBeginningBalance());
        this.setSummary(baseData, row.get("Summary"));
        dataList.add(baseData);
    }

    private void setSummary(OnlineGeneralLedger base, JsonNode summary) {
        if (ObjectUtils.isEmpty(summary) || ObjectUtils.isEmpty(summary.get("ColData"))) {
            return;
        }
        List<JsonNode> list = Lists.newArrayList(summary.get("ColData").elements());
        if (CollectionUtils.isNotEmpty(list) && list.size() > 2){
            base.setName(super.getStringValue(list.get(0).get("value")));
            base.setAmount(super.getDoubleValue(list.get(list.size() - 2).get("value")));
        }
    }

    private void setColData(OnlineGeneralLedger base, List<JsonNode> list) {
        List<JsonNode> firstList = Lists.newArrayList(list.get(0).get("ColData").elements());
        if (CollectionUtils.isNotEmpty(firstList)
                && "Beginning Balance".equalsIgnoreCase(super.getStringValue(firstList.get(0).get("value")))){
            base.setBeginningBalance(super.getDoubleValue(firstList.get(firstList.size()-1).get("value")));
            if (list.size() == 1){
                base.setBalance(base.getBeginningBalance());
                return;
            }
        }

        List<JsonNode> lastList = Lists.newArrayList(list.get(list.size()-1).get("ColData").elements());
        if (CollectionUtils.isNotEmpty(lastList)){
            base.setBalance(super.getDoubleValue(lastList.get(lastList.size()-1).get("value")));
        }
    }

    private void setHeaderColData(OnlineGeneralLedger base, JsonNode colData, Boolean isRoot) {
        if (ObjectUtils.isEmpty(colData)) {
            return;
        }
        Iterator<JsonNode> colDataIterator = colData.elements();
        if (colDataIterator.hasNext()) {
            JsonNode data = colDataIterator.next();
            if (isRoot){
                base.setAccountId(super.getIntegerValue(data.get("id")));
                base.setAccountName(super.getStringValue(data.get("value")));
            }else{
                base.setSubAccountId(super.getIntegerValue(data.get("id")));
                base.setSubAccountName(super.getStringValue(data.get("value")));
            }
        }
    }

}
